/*
 * @Author: 黄威
 * @Date: 2021-10-28 10:47:30
 * @LastEditors: 黄威
 * @LastEditTime: 2022-03-21 11:44:15
 * @Description: 分析插件
 */
import type {
    BindMap,
    DrawOptions,
    DrawType,
    GraphicLayer,
    AnalysisOption,
} from 'types'

import * as turf from '@turf/turf'
import getAnalysis from '@/services/analysis'

// 开始 绘制-分析
function analysis(
    plugin: AnalysisPlugin,
    drawType: DrawType,
    options: DrawOptions,
    events: any,
    tipMessage: string = '左键点击添加点绘制！'
) {
    plugin.vm.startDraw(
        drawType,
        {
            ...options,
            layer: plugin.layer,
            repeatMode: true,
            events,
        },
        tipMessage
    )
}

const ext = {
    // 坐标转换
    _coordtoP(coord: any) {
        return { x: coord[0], y: coord[1], z: 0 }
    },
    // 角度
    _proBearing(du: number) {
        let angle = du + 90

        if (angle >= 360) angle -= 360

        return angle
    },
    // 构造可视域分析参数
    _processData(
        firstLatLng: any,
        secondLatLng: any,
        thirdLatLng: any,
        bindMap: BindMap
    ) {
        const rad = Math.atan2(
            firstLatLng[1] - secondLatLng[1],
            secondLatLng[0] - firstLatLng[0]
        )
        let angle = (rad * 180) / Math.PI
        if (angle < 0) {
            angle += 360
        }
        const rad1 = Math.atan2(
            firstLatLng[1] - thirdLatLng[1],
            thirdLatLng[0] - firstLatLng[0]
        )
        let angle1 = (rad1 * 180) / Math.PI
        if (angle1 < 0) {
            angle1 += 360
        }

        // 中心点
        const center = turf.point([firstLatLng[0], firstLatLng[1]]) // 圆心点

        // 半径
        const radius = Math.max(
            turf.distance(
                center,
                turf.point([secondLatLng[0], secondLatLng[1]]),
                {
                    units: 'degrees',
                }
            ),
            turf.distance(
                center,
                turf.point([thirdLatLng[0], thirdLatLng[1]]),
                { units: 'degrees' }
            )
        )

        const startAngle = 360 - angle1 // 开始
        // 夹角
        let viewAngle = angle1 - angle
        if (viewAngle < 0) viewAngle += 360

        // 获取扇形
        const bearing = this._proBearing(angle)
        const arc = turf.sector(center, radius, bearing, bearing + viewAngle, {
            units: 'degrees',
        })
        const [minx, miny, maxx, maxy] = turf.bbox(arc)
        const firstPoint = bindMap.getPixel4MapCoords([minx, miny])
        const secondPoint = bindMap.getPixel4MapCoords([maxx, maxy])

        const obj = {
            radius: radius,
            startAngle: startAngle,
            viewAngle: viewAngle,
            imgWidth: Math.abs(firstPoint.x - secondPoint.x),
            imgHeigth: Math.abs(firstPoint.y - secondPoint.y),
            bounds: [
                [minx, miny],
                [maxx, maxy],
            ],
        }
        return obj
    },
    // 坡度分析
    _proSlopeData(data: any, bindMap: BindMap) {
        const pxs = []
        const pys = []

        for (let i = 0; i < 4; i++) {
            const point = bindMap.getPixel4MapCoords(data[i])
            pxs.push(point.x)
            pys.push(point.y)
        }

        const minx = Math.min(...pxs)
        const maxx = Math.max(...pxs)
        const miny = Math.min(...pys)
        const maxy = Math.max(...pys)

        const height = Math.abs(parseInt(String(maxy - miny)))
        const width = Math.abs(parseInt(String(maxx - minx)))

        const obj = {
            width: width,
            height: height,
        }
        return obj
    },
}

export default class AnalysisPlugin {
    static extends = ['startAnalysis', 'clearAnalysis']

    vm: BindMap
    layer: GraphicLayer
    service: ReturnType<typeof getAnalysis>

    constructor(vm: BindMap, options: AnalysisOption) {
        this.vm = vm
        this.layer = vm.newGraphicLayer()
        this.service = getAnalysis(options)
    }

    startAnalysis(type: string, options: DrawOptions = {}) {
        if (type in this && type !== 'startAnalysis') {
            ;(this as any)[type](options)
        } else {
            throw '不支持的分析类型！'
        }
    }

    // 高程分析
    calculateAltitude(options: DrawOptions = {}) {
        analysis(this, 'Marker', options, {
            drawcreate: (evt: any) => {
                this.service.calculateAltitude(evt.coords[0]).then(data => {
                    const labelStyle = Object.assign(
                        {
                            text: `经度：${data.x.toFixed(
                                6
                            )}\n纬度：${data.y.toFixed(
                                6
                            )}\n高程：${data.z.toFixed(4)} m`,
                            border: true,
                            borderColor: 'red',
                            fill: true,
                            anchor: 'left',
                            // 三维样式
                            disableDepthTestDistance: Number.POSITIVE_INFINITY,
                        },
                        options.style
                    )
                    this.vm.drawGraphic(
                        'Label',
                        evt.coords,
                        labelStyle,
                        null,
                        this.layer
                    )
                })
            },
        })
    }

    // 坡度分析
    calculateSlopeOrAspect(options: DrawOptions = {}) {
        analysis(this, 'Rectangle', options, {
            drawcreate: (evt: any) => {
                const [[x1, y1], [x2, y2]] = evt.coords

                const pointData = [
                    [+x1, +y1],
                    [+x1, +y2],
                    [+x2, +y2],
                    [+x2, +y1],
                ]

                const params = ext._proSlopeData(pointData, this.vm)
                this.service
                    .calculateSlopeOrAspect({
                        points: pointData,
                        ...params,
                    })
                    .then(res => {
                        this.vm.drawGraphic(
                            'Image',
                            evt.coords,
                            {
                                img: res.image,
                                opacity: 0.85,
                            },
                            null,
                            this.layer
                        )
                    })
            },
        })
    }

    // 可视域分析
    viewShed(options: DrawOptions = {}) {
        // 点集合
        const coords = new Map()

        analysis(this, 'Polygon', options, {
            drawcreate: () => coords.clear(),
            drawchange: (evt: any) => {
                // 中心点
                if (!coords.get('center')) {
                    coords.set('center', ext._coordtoP(evt.value))

                    this.service.calculateAltitude(evt.value).then(data => {
                        coords.set('center', data)
                    })
                }

                if (evt.coords.length === 2) {
                    // 结束多边形绘制
                    evt.handler.finishShape()

                    const cPoint = coords.get('center') //中心点

                    const shanxing = ext._processData(
                        [cPoint.x, cPoint.y],
                        evt.coords[1],
                        evt.value,
                        this.vm
                    )
                    this.service
                        .viewShed({
                            point: [cPoint.x, cPoint.y, cPoint.z],
                            imgWidth: shanxing.imgWidth * 2,
                            imgHeigth: shanxing.imgHeigth * 2,
                            viewRadius: shanxing.radius,
                            startAngle: shanxing.startAngle,
                            viewAngle: shanxing.viewAngle,
                        })
                        .then(res => {
                            this.vm.drawGraphic(
                                'Image',
                                shanxing.bounds,
                                {
                                    img: res.image,
                                    opacity: 0.85,
                                },
                                null,
                                this.layer
                            )
                        })
                }
            },
        })
    }

    // 通视分析
    isVisible(options: DrawOptions = {}) {
        analysis(this, 'Polyline', options, {
            drawchange: (evt: any) => {
                if (evt.coords.length === 1) {
                    evt.handler.finishShape()
                    this.service
                        .isVisible(evt.coords[0], evt.value)
                        .then(resData => {
                            if (resData.visible) {
                                // 可见线
                                this.vm.drawGraphic(
                                    'Polyline',
                                    [evt.coords[0], evt.value],
                                    { color: '#00ffad' },
                                    null,
                                    this.layer
                                )
                            } else {
                                this.vm.drawGraphic(
                                    'Polyline',
                                    [
                                        evt.coords[0],
                                        [resData.barrier.x, resData.barrier.y],
                                    ],
                                    { color: '#00ffad' },
                                    null,
                                    this.layer
                                )
                                this.vm.drawGraphic(
                                    'Polyline',
                                    [
                                        [resData.barrier.x, resData.barrier.y],
                                        evt.value,
                                    ],
                                    { color: 'red' },
                                    null,
                                    this.layer
                                )
                            }
                        })
                }
            },
        })
    }

    // 清空分析
    clearAnalysis() {
        this.layer.clear()
    }
}
